#pragma once

#include "IWebsocketServer.h"
#include <gio/gnetworking.h>
#include <glib.h>
#include <nice/agent.h>
#include "WDtlsSrtp.h"
#include <iostream>
#include <thread>
#include <map>
#include "rtp_rtcp.h"
#include "CommonSignalData.h"
#include "h264frame.h"

#define MAX_RTP_PKT_LENGTH  1400

class IIceRecvCb
{
public:
    virtual void handleRecvRtp(shared_ptr<WsRequestMsg> wsRequest, char *data, int len) = 0;
};

class WIceAgent
{
public:
    WIceAgent(IWebsocketServer *wsServer, shared_ptr<WsRequestMsg> wsRequest, gboolean controlling,
              const gchar* stun_addr = "stun.l.google.com", guint stun_port = 19302);
    virtual ~WIceAgent();
    static void init();
    static void release();

    bool startGather(int32_t streamid);
    int32_t addStream(const char* szstreamname, uint32_t componentnum);
    bool setIceRecvCb(IIceRecvCb *iceRecvCb);
    bool setRemoteSdp(const char* sdp);
    bool setRemoteCandidate(const char* szcandidate);
    bool sendData(int32_t streamid, uint32_t componentid, guint len, gchar *buf);
    bool sendDataNeedProtect(int32_t streamid, uint32_t componentid, guint len, gchar *buf);

private:
    IWebsocketServer *_wsServer = nullptr;
    WDtlsSrtp *_dtlsSrtp = nullptr;
    NiceAgent *_iceAgent = nullptr;
    shared_ptr<WsRequestMsg> _wsRequest = nullptr;
    std::map<int32_t, uint32_t> _streamComponetMap;
    std::string _remoteSdp;
    std::thread *_videoSendThread = nullptr;
    volatile bool _stopVideoSendFlag = false;
    IIceRecvCb *_iceRecvCb = nullptr;

    static GMainLoop *s_gloop;
    static GThread *s_gloopthread;

    void candidateGatheringDone(int32_t stream_id);
    void componentStateChanged(int32_t streamid, uint32_t componentid, guint state);
    void newSelectedPairFull(guint stream_id,guint component_id, NiceCandidate *lcandidate, NiceCandidate* rcandidate);
    void niceRecvData(int32_t streamid, uint32_t componentid, guint len, gchar *buf);
    void readSendVideo();

    static void* loopThread(void *data);
    static void cbCandidateGatheringDone(NiceAgent *agent, guint stream_id, gpointer data);
    static void cbComponentStateChanged(NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data);
    static void cbNewSelectedPairFull(NiceAgent* agent, guint stream_id,guint component_id, NiceCandidate *lcandidate,
                                          NiceCandidate* rcandidate, gpointer data);
    static void cbNiceRecv(NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer data);
    static void getRtspRtpVideoTotalLen(const uint8_t* pbuffer, uint32_t dwbuflen, uint32_t& ntotallen, uint32_t& numbernalus);
    static void setBufRtpVideoHeader(uint8_t* pbuffer, uint32_t dwssrc, uint32_t dwtimestample, uint16_t dwseqnum, bool marker);
};

